#include "PanSeries.h"
#include "pan_lp.h"
#include "pan_clk.h"

/**
* @brief  This function enable gpio p56 wake up 
* @param[in]  ana: where ana is analog module
* @param[in]  WkEdge: wake up edge select,0-->low,1-->high 
* @return   none
*/
void LP_SetExternalWake(ANA_T *ana,uint8_t WkEdge)
{
	if(WkEdge){
		ana->LP_FL_CTRL_3V |= ANAC_FL_EXT_WAKEUP_SEL_Msk_3v;
	}else{
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_EXT_WAKEUP_SEL_Msk_3v;
	}
}

/**
* @brief  This function set sleep time
* @param[in]  ana: where ana is analog module
* @param[in]  u32ClkCnt: where u32ClkCnt is 32k clock cnt num
* @param[in]  idx: where idx is 0,1, 2
* @return   none
*/
void LP_SetSleepTime(ANA_T *ana,uint32_t u32ClkCnt,uint8_t idx)
{
	((__IO uint32_t *)(&(ana)->LP_SPACING_TIME0))[idx] = u32ClkCnt;
}


/**
* @brief  This function set delay time used for standby_m0 mode for wait LPLDOH ready
* @param[in]  ana: where ana is analog module
* @param[in]  u8Clk32Cnt: where u8Clk32Cnt is 32k clock period cnt
* @return   none
*/
void LP_SetLpldohDelay(ANA_T *ana,uint16_t u16Clk32Cnt)
{
	uint32_t tmp_reg;

	tmp_reg = ana->LP_DLY_CTRL_3V;
	tmp_reg &= ~(ANAC_LPLDOH_DLY_TIME_Msk_3v);
	tmp_reg |= (u16Clk32Cnt << ANAC_LPLDOH_DLY_TIME_Pos_3v);
	ana->LP_DLY_CTRL_3V = tmp_reg;
}

/**
* @brief  This function set delay time used for fast clock ready
* @param[in]  ana: where ana is analog module
* @param[in]  u8Clk32Cnt: where u8Clk32Cnt is 32k clock period cnt
* @return   none
*/
void LP_SetWakeDelay(ANA_T *ana,uint16_t u16Clk32Cnt)
{
	uint32_t tmp_reg;

	tmp_reg = ana->LP_DLY_CTRL_3V;
	tmp_reg &= ~(ANAC_32KCLK_DLY_TIME_Msk);
	tmp_reg |= (u16Clk32Cnt << ANAC_32KCLK_DLY_TIME_Pos);
	ana->LP_DLY_CTRL_3V = tmp_reg;
}

/**
* @brief  This function set delay time used for fast clock ready
* @param[in]  ana: where ana is analog module
* @param[in]  mode: where mode is sleep mode select
*                        LP_MODE_SEL_SLEEP_MODE
*                        LP_MODE_SEL_DEEPSLEEP_MODE
*                        LP_MODE_SEL_STANDBY_M1_MODE
*                        LP_MODE_SEL_STANDBY_M0_MODE
*
* @return   none
*/

void LP_SetSleepMode(ANA_T *ana,uint8_t mode)
{
	uint32_t tmp_reg;

	tmp_reg = ana->LP_FL_CTRL_3V;
	tmp_reg &= ~(ANAC_FL_SLEEP_MODE_SEL_Msk);
	tmp_reg |= (mode << ANAC_FL_SLEEP_MODE_SEL_Pos);
	ana->LP_FL_CTRL_3V = tmp_reg;
}


 /**
* @brief  This function set sleep mode config
* @param[in]  ana: where ana is analog module
* @param[in]  u8ExtWkDis: where u8ExtWkDis determine whether to wake up by GPIO
*																									0:gpio can wake up
*																									1:gpio can notwake up
* @return   none
*/
void LP_SetSleepModeConfig(ANA_T *ana,uint32_t wkMode,bool enterCyclically)
{	
	LP_EnableInt(ana,ENABLE);
	LP_SetSleepMode(ana, LP_MODE_SEL_SLEEP_MODE);
	if((LP_WKUP_MODE_SEL_EXT_GPIO != wkMode)&&(LP_WKUP_MODE_SEL_GPIO != wkMode)){
		ana->LP_FL_CTRL_3V |= ANAC_FL_RC32K_EN_Msk_3v;
		ana->LP_FL_CTRL_3V |= ANAC_FL_SLEEP_CNT_EN_Msk;
	} else {
        ana->LP_FL_CTRL_3V &= ~ANAC_FL_SLEEP_CNT_EN_Msk;
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
    }
#ifdef SYNC_3V_REG_MANUALLY
    CLK_Wait3vSyncReady();
#endif
	SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
	if(enterCyclically)
		SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
	else
		SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
	__WFI();
#ifdef SYNC_3V_REG_MANUALLY
    CLK_Wait3vSyncReady();
#endif
}

void LP_SetDeepSleepConfig(ANA_T *ana,
							uint32_t wkMode,
							bool enterCyclically,
							uint8_t PowerCtrl,
							uint8_t dp_mode)
{
	LP_EnableInt(ana,ENABLE);
	if (dp_mode == LP_DEEPSLEEP_MODE1){
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |= ANAC_LDO_POWER_CTL_Msk | ANAC_FL_LDO_ISOLATE_EN_Msk;
		ana->LP_FL_CTRL_3V &= ~ANAC_LDOL_POWER_CTL_Msk;
	} else if (dp_mode == LP_DEEPSLEEP_MODE2){
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V &= ~ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |= ANAC_LDOL_POWER_CTL_Msk | ANAC_LDO_POWER_CTL_Msk;
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_LDO_ISOLATE_EN_Msk;
	} else if (dp_mode == LP_DEEPSLEEP_MODE3){
		ana->LP_LP_LDO_3V &= ~ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |= ANAC_LDOL_POWER_CTL_Msk | ANAC_LDO_POWER_CTL_Msk;
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_LDO_ISOLATE_EN_Msk;
	}

    // Enable flash power in lp mode (Also need to enable flash AutoDp to save power)
//	ana->LP_FL_CTRL_3V |= ANAC_FL_FLASH_BP_EN_Msk;

	LP_SetSleepMode(ana, LP_MODE_SEL_DEEPSLEEP_MODE);
	if((LP_WKUP_MODE_SEL_EXT_GPIO != wkMode)&&(LP_WKUP_MODE_SEL_GPIO != wkMode)){
		if (CLK->CLK_TOP_CTRL_3V & CLK_TOPCTL_32K_CLK_SEL_Msk_3v) {
			ana->LP_FL_CTRL_3V |= ANAC_FL_XTAL32K_EN_Msk_3v;
			ana->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
		} else {
			ana->LP_FL_CTRL_3V &= ~ANAC_FL_XTAL32K_EN_Msk_3v;
			ana->LP_FL_CTRL_3V |= ANAC_FL_RC32K_EN_Msk_3v;
		}
		ana->LP_INT_CTRL |= ANAC_INT_SLEEP_TMR_WK_EN_Msk;
	} else {
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
    }

	ana->LP_FL_CTRL_3V = ((PowerCtrl & 0x1f) << 24u) | (ana->LP_FL_CTRL_3V & 0xe0FFFFFF);

	// Wait 3v sync ready manually
	ANA->LP_REG_SYNC |= ANAC_LP_REG_SYNC_3V_Msk | ANAC_LP_REG_SYNC_3V_TRG_Msk;
	while(ANA->LP_REG_SYNC & (ANAC_LP_REG_SYNC_3V_TRG_Msk)) {}

	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	if(enterCyclically)
		SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
	else
		SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
	ANA->LP_INT_CTRL |= ANAC_INT_SLEEP_TMR_INT_EN_Msk;
	__WFI();
}


void LP_SetStandbyMode0Config(void)
{
	LP_SetSleepMode(ANA, LP_MODE_SEL_STANDBY_M0_MODE);
	LP_EnableInt(ANA,ENABLE);
	ANA->LP_FL_CTRL_3V &= ~ANAC_FL_XTAL32K_EN_Msk_3v;
	ANA->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
	#ifdef SYNC_3V_REG_MANUALLY
	CLK_Wait3vSyncReady();
	#endif

	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__WFI();
}

void LP_SetStandbyMode0BodLvrConfig(void)
{
	LP_SetSleepMode(ANA, LP_MODE_SEL_STANDBY_M0_MODE);
	LP_EnableInt(ANA,ENABLE);
	//bod/lvr wakeup need
	ANA->LP_FL_CTRL_3V |= ANAC_FL_XTAL32K_EN_Msk_3v;
	ANA->LP_FL_CTRL_3V |= ANAC_FL_RC32K_EN_Msk_3v;
	#ifdef SYNC_3V_REG_MANUALLY
	CLK_Wait3vSyncReady();
	#endif

	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__WFI();
}

void LP_SetStandbyMode1Config(ANA_T *ana,
							uint32_t wkMode,
							uint8_t PowerCtrl,
							uint32_t slpTimer,
							uint8_t spaceIdx,
							uint8_t stdy_mode)
{
	LP_SetSleepMode(ana, LP_MODE_SEL_STANDBY_M1_MODE);
	LP_EnableInt(ana,ENABLE);
	if (stdy_mode == LP_STANDBY_M1_MODE1){
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |=  ANAC_FL_LDO_ISOLATE_EN_Msk;
		ana->LP_FL_CTRL_3V &= ~(ANAC_LDOL_POWER_CTL_Msk | ANAC_LDO_POWER_CTL_Msk);
	} else if (stdy_mode == LP_STANDBY_M1_MODE2){
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V &= ~ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |= ANAC_LDOL_POWER_CTL_Msk | ANAC_FL_LDO_ISOLATE_EN_Msk;
		ana->LP_FL_CTRL_3V &= ~(ANAC_LDO_POWER_CTL_Msk);
	} else if (stdy_mode == LP_STANDBY_M1_MODE3){
		ana->LP_LP_LDO_3V &= ~ANAC_LPLDO_H_EN_Msk_3v;
		ana->LP_LP_LDO_3V |= ANAC_LPLDO_L_EN_Msk;
		ana->LP_FL_CTRL_3V |= ANAC_LDOL_POWER_CTL_Msk | ANAC_FL_LDO_ISOLATE_EN_Msk;
		ana->LP_FL_CTRL_3V &= ~(ANAC_LDO_POWER_CTL_Msk);
	}
	
	ana->LP_FL_CTRL_3V = ((PowerCtrl & 0x1f) << 24u) | (ana->LP_FL_CTRL_3V & 0xe0FFFFFF);
	if((LP_WKUP_MODE_SEL_EXT_GPIO != wkMode)&&(LP_WKUP_MODE_SEL_GPIO != wkMode)){
		if (CLK->CLK_TOP_CTRL_3V & CLK_TOPCTL_32K_CLK_SEL_Msk_3v) {
			ana->LP_FL_CTRL_3V |= ANAC_FL_XTAL32K_EN_Msk_3v;
			ana->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
		} else {
			ana->LP_FL_CTRL_3V &= ~ANAC_FL_XTAL32K_EN_Msk_3v;
			ana->LP_FL_CTRL_3V |= ANAC_FL_RC32K_EN_Msk_3v;
		}
		ana->LP_INT_CTRL |= ANAC_INT_SLEEP_TMR_WK_EN_Msk;
	} else {
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_RC32K_EN_Msk_3v;
		ana->LP_FL_CTRL_3V &= ~ANAC_FL_XTAL32K_EN_Msk_3v;
	}

	// Wait 3v sync ready manually
	ANA->LP_REG_SYNC |= ANAC_LP_REG_SYNC_3V_Msk | ANAC_LP_REG_SYNC_3V_TRG_Msk;
	while(ANA->LP_REG_SYNC & (ANAC_LP_REG_SYNC_3V_TRG_Msk)) {}

	if((LP_WKUP_MODE_SEL_EXT_GPIO != wkMode)&&(LP_WKUP_MODE_SEL_GPIO != wkMode)){
		LP_SetSleepTime(ana,slpTimer,spaceIdx);
	}
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
	__WFI();
}
